home *** CD-ROM | disk | FTP | other *** search
- /*
- ** server2.c
- **
- ** Written by Dale Larson, Software Engineer, Commodore-Amiga, Inc.
- ** Copyright 1991, Commodore-Amiga, Inc.
- ** Permission to use granted provided this notice remains intact.
- **
- ** This is a version of the ncopy server which processes multiple requests
- ** simultaneously. It spawns multiple processes to do so (it could also
- ** use selectwait() to do [see server3.c]). It is more complex than the
- ** simple server, but not much, and it is nicer under frequent and/or heavy
- ** use. It also allows users to copy a file from one location on a remote
- ** machine to another location on the same remote machine (i.e.
- ** "ncopy sprite!ram:x sprite!work:y"). A system requester will not
- ** pop up if the server recieves a request to read/write to/from a
- ** non-existent device.
- **
- ** This server has no provision for exiting.
- **
- ** You should be familiar with the ncopy client (ncopy.c and transfer.c) and
- ** the simple ncopy server (server1.c) before studying this server.
- **
- ** Thanks to Randell Jessup for his idea on how to easily arbitrate access
- ** to the global Ns (which is used to pass info to child processes).
- */
-
-
- #include "ncopy.h"
-
- struct Library *SockBase;
- #define MAXSOCKS 10
-
- char vers[] = "\0$VER: server2 1.0 (25.02.91)";
-
- void send_file(int s, BPTR file);
- void get_file(int s, BPTR file);
- void handle_request(void);
- int init(void);
-
- /* Not in SAS 5.10 or Manx 5.0d includes */
- struct Process *CreateNewProcTags( unsigned long tag1type, ... );
-
- /* global variable for New socket read by new processes: */
- int Ns = 0;
-
-
- /*
- ** main()
- **
- ** Call init() then wait to accept connections. Once a connection has been
- ** accepted, start a new process to execute the handler function with the
- ** socket which accept() connected to a remote machine. Go back to accepting
- ** connections.
- */
- main(int argc, char **argv)
- {
- int s; /* socket to accept connections on */
- struct Process *pid;
-
- s = init();
-
- /*
- ** Accept connections from s and process them on ns.
- */
- while(1)
- {
- /*
- ** Make sure that there is not a child process which hasn't
- ** had a chance to copy its socket. Ns must be initialized
- ** to zero before this while() and children must set Ns
- ** to zero when they have copied it.
- */
- if(Ns)
- {
- Delay(1);
- continue;
- }
- if( (Ns = accept(s,NULL,NULL)) >= 0 )
- {
- static char proc_name[20];
-
- sprintf(proc_name, "ncopy server #%2d", Ns);
- pid = CreateNewProcTags(NP_Entry, (LONG)handle_request,
- NP_Name, (LONG)proc_name,
- NP_WindowPtr, -1L,
- TAG_DONE);
- if(!pid)
- {
- s_close(Ns);
- Ns = 0;
- }
- }
- }
- }
-
-
- /*
- ** init()
- **
- ** Get a socket, bind a name to it, express a willingness to accept
- ** connections to it (listen) and return the socket. Exit on error.
- */
- int init(void)
- {
- struct sockaddr_in sin; /* socket address (internet) to establish */
- int s, /* socket to accept connections on */
- len = sizeof(sin);
-
- /* Open Shared Socket library:
- */
- if(SockBase = OpenLibrary( "inet:libs/socket.library", 0L ))
- {
- setup_sockets( MAXSOCKS, &errno );
- }else
- {
- puts("Can't open socket.library.");
- exit(RETURN_ERROR);
- }
-
- /*
- ** Initialize a socket.
- */
- if( (s = socket(AF_INET, SOCK_STREAM, 0)) < 0)
- {
- perror("socket");
- exit(RETURN_ERROR);
- }
-
- /*
- ** Bind name to socket.
- ** Since we got sin off the stack, it could contain anything, and so
- ** we zero it before initializing it.
- */
- bzero(&sin, len);
- sin.sin_family = AF_INET;
- /*
- ** While prototyping a program, pick an unused port number above
- ** 1024 like I did here. For a real program, assign a name and a
- ** port number above 1024 and stick it in inet:db/servers on all
- ** machines which will use the application. That way the user can
- ** reconfigure port numbers used by new applications if necessary.
- ** You can modify the server to get the port number from the
- ** database by using code like this (instead of "sin.sin_port=
- ** htons(6666)" below):
- **
- ** struct servent *servptr;
- ** char serv[] = "servicename";
- **
- ** if( (servptr = getservbyname(serv, "tcp")) == NULL)
- ** {
- ** printf("Unknown service %s. Check inet:db/services.\n",serv);
- ** return RETURN_ERROR;
- ** }
- ** sin.sin_port = servptr->s_port;
- */
- sin.sin_port = htons(6666);
- sin.sin_addr.s_addr = INADDR_ANY;
- if(bind(s, (struct sockaddr *)&sin, len) < 0)
- {
- perror("bind");
- exit(RETURN_ERROR);
- }
-
- /*
- ** Put socket into "listen" state (ready to accept connections).
- */
- listen(s,5);
- return s;
- }
-
-
- /*
- ** handle_request()
- **
- ** Handles a request to send or receive a file on a given socket.
- ** Handling a request consists of the following:
- ** 1) receive the mode (send or receive -- MODE_OLDFILE or MODE_NEWFILE)
- ** 2) receive the filename
- ** 3) attempt to open the file
- ** 4) return "\0" for succesful open,
- ** specially formated informative error message otherwise
- ** 5) call function to send or receive the file
- ** 6) closes the file we opened and the socket we were passed
- */
- void handle_request(void)
- {
- int s; /* socket passed by parent */
- char buffer[LENGTH];
- int mode; /* AmigaDOS file open mode (MODE_OLDFILE or MODE_NEWFILE) */
- BPTR file; /* BCPL pointer to an AmigaDOS file handle */
-
- geta4();
-
-
- s = Ns;
- Ns = 0; /* So that parent may feel free to use it again */
-
-
- /* Get the mode.
- ** Don't worry about making sure that we got what we wanted because we
- ** can't really screw anything up and we can't send an error message
- ** if our communcications are error-prone.
- */
- recv(s, (char *)&mode, sizeof(int), 0);
-
- /* Get the filename which we'll read or write (depending on mode).
- ** (Assume that we get only null-terminated strings.)
- */
- recv(s, buffer, LENGTH, 0);
-
- /*
- ** Attempt to open file.
- */
- if( !(file = Open(buffer, mode)) )
- {
- int len;
-
- len = strlen(buffer);
- strncat(buffer, "': ", LENGTH-4); /* 4 not 3 'cause of nul */
- Fault(IoErr(), NULL, buffer+len+3, LENGTH-len-4);
- send(s, buffer, strlen(buffer)+1, 0);
- s_close(s);
- return;
- }
-
- /*
- ** Indicate succesful opening of file.
- */
- send(s, "\0", 1, 0);
-
- /*
- ** Send or recieve the file.
- */
- if(mode == MODE_OLDFILE)
- send_file(s, file);
- else
- get_file(s, file);
-
- Close(file);
- s_close(s);
- }
-
-
- void send_file(int s, BPTR file)
- {
- char buffer[LENGTH];
- long actualLength;
-
- do
- {
- actualLength = Read(file, (void *)buffer, LENGTH);
- if(actualLength < 0)
- return; /* Error, but we have no way to report it. */
- if(send(s, buffer, actualLength, 0) < 0)
- return; /* Error, but we have no way to report it. */
- }while(actualLength);
- }
-
-
- void get_file(int s, BPTR file)
- {
- char buffer[LENGTH];
- int n;
-
- do
- {
- n = recv(s, buffer, LENGTH, 0);
- if(n < 0)
- return; /* Error, but we have no way to report it. */
- if(Write(file, (void *)buffer, n) < 0)
- return; /* Error, but we have no way to report it. */
- }while(n);
- }
-